using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using SeataNet.Core.Common;
using SeataNet.Core.RPC;

namespace SeataNet.Core.Cluster
{
    /// <summary>
    /// 故障转移策略
    /// </summary>
    public enum FailoverStrategy
    {
        /// <summary>
        /// 快速失败
        /// </summary>
        FailFast,

        /// <summary>
        /// 故障转移
        /// </summary>
        Failover,

        /// <summary>
        /// 安全重试
        /// </summary>
        SafeRetry,

        /// <summary>
        /// 降级处理
        /// </summary>
        Fallback
    }

    /// <summary>
    /// 故障转移管理器接口
    /// </summary>
    public interface IFailoverManager
    {
        /// <summary>
        /// 启动故障转移管理器
        /// </summary>
        Task StartAsync(CancellationToken cancellationToken = default);

        /// <summary>
        /// 停止故障转移管理器
        /// </summary>
        Task StopAsync(CancellationToken cancellationToken = default);

        /// <summary>
        /// 执行带故障转移的操作
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="operation">操作</param>
        /// <param name="xid">事务ID</param>
        /// <param name="key">选择键（用于负载均衡）</param>
        /// <returns>操作结果</returns>
        Task<T> ExecuteWithFailoverAsync<T>(Func<ClusterNode, Task<T>> operation, string? xid = null, string? key = null);

        /// <summary>
        /// 标记节点为故障状态
        /// </summary>
        /// <param name="nodeId">节点ID</param>
        /// <param name="exception">异常信息</param>
        void MarkNodeAsFailed(string nodeId, Exception exception);

        /// <summary>
        /// 标记节点为恢复状态
        /// </summary>
        /// <param name="nodeId">节点ID</param>
        void MarkNodeAsRecovered(string nodeId);

        /// <summary>
        /// 检查节点是否故障
        /// </summary>
        /// <param name="nodeId">节点ID</param>
        /// <returns>是否故障</returns>
        bool IsNodeFailed(string nodeId);

        /// <summary>
        /// 获取故障节点列表
        /// </summary>
        /// <returns>故障节点列表</returns>
        List<FailedNode> GetFailedNodes();

        /// <summary>
        /// 获取故障转移统计信息
        /// </summary>
        /// <returns>故障转移统计信息</returns>
        FailoverStatistics GetFailoverStatistics();
    }

    /// <summary>
    /// 默认故障转移管理器实现
    /// </summary>
    public class DefaultFailoverManager : IFailoverManager, IDisposable
    {
        private readonly ILogger<DefaultFailoverManager> _logger;
        private readonly IOptionsMonitor<ClusterConfiguration> _clusterConfiguration;
        private readonly IOptionsMonitor<FailoverConfiguration> _failoverConfiguration;
        private readonly IClusterManager _clusterManager;
        private readonly ILoadBalancer _loadBalancer;
        private readonly IRpcClient _rpcClient;

        private readonly ConcurrentDictionary<string, FailedNode> _failedNodes;
        private readonly ConcurrentDictionary<string, FailoverStatistics> _transactionStatistics;
        private Timer? _recoveryTimer;
        private bool _disposed = false;
        private bool _isRunning = false;

        public DefaultFailoverManager(
            ILogger<DefaultFailoverManager> logger,
            IOptionsMonitor<ClusterConfiguration> clusterConfiguration,
            IOptionsMonitor<FailoverConfiguration> failoverConfiguration,
            IClusterManager clusterManager,
            ILoadBalancer loadBalancer,
            IRpcClient rpcClient)
        {
            _logger = logger;
            _clusterConfiguration = clusterConfiguration;
            _failoverConfiguration = failoverConfiguration;
            _clusterManager = clusterManager;
            _loadBalancer = loadBalancer;
            _rpcClient = rpcClient;
            _failedNodes = new ConcurrentDictionary<string, FailedNode>();
            _transactionStatistics = new ConcurrentDictionary<string, FailoverStatistics>();
        }

        public async Task StartAsync(CancellationToken cancellationToken = default)
        {
            if (_isRunning)
            {
                _logger.LogDebug("Failover manager is already running");
                return;
            }

            _isRunning = true;
            _logger.LogInformation("Starting failover manager");

            var config = _failoverConfiguration.CurrentValue;

            // 启动恢复定时器
            _recoveryTimer = new Timer(
                async _ => await CheckFailedNodesAsync(),
                null,
                TimeSpan.FromSeconds(config.RecoveryCheckIntervalSeconds),
                TimeSpan.FromSeconds(config.RecoveryCheckIntervalSeconds));

            _logger.LogInformation("Failover manager started successfully");
        }

        public async Task StopAsync(CancellationToken cancellationToken = default)
        {
            if (!_isRunning)
            {
                _logger.LogDebug("Failover manager is not running");
                return;
            }

            _isRunning = false;
            _logger.LogInformation("Stopping failover manager");

            // 停止定时器
            _recoveryTimer?.Dispose();

            _logger.LogInformation("Failover manager stopped");
        }

        public async Task<T> ExecuteWithFailoverAsync<T>(Func<ClusterNode, Task<T>> operation, string? xid = null, string? key = null)
        {
            var config = _failoverConfiguration.CurrentValue;
            var clusterNodes = _clusterManager.GetAvailableNodes();
            var attemptedNodes = new List<string>();

            // 根据策略执行操作
            switch (config.Strategy)
            {
                case FailoverStrategy.FailFast:
                    return await ExecuteFailFastAsync(operation, clusterNodes, attemptedNodes, xid);

                case FailoverStrategy.Failover:
                    return await ExecuteFailoverAsync(operation, clusterNodes, attemptedNodes, xid, key);

                case FailoverStrategy.SafeRetry:
                    return await ExecuteSafeRetryAsync(operation, clusterNodes, attemptedNodes, xid, key);

                case FailoverStrategy.Fallback:
                    return await ExecuteFallbackAsync(operation, clusterNodes, attemptedNodes, xid, key);

                default:
                    _logger.LogWarning("Unknown failover strategy: {Strategy}, using Failover", config.Strategy);
                    return await ExecuteFailoverAsync(operation, clusterNodes, attemptedNodes, xid, key);
            }
        }

        public void MarkNodeAsFailed(string nodeId, Exception exception)
        {
            if (_failedNodes.TryGetValue(nodeId, out var failedNode))
            {
                // 更新现有故障节点
                failedNode.FailureCount++;
                failedNode.LastFailureTime = DateTime.UtcNow;
                failedNode.LastException = exception;
            }
            else
            {
                // 添加新故障节点
                _failedNodes[nodeId] = new FailedNode
                {
                    NodeId = nodeId,
                    FirstFailureTime = DateTime.UtcNow,
                    LastFailureTime = DateTime.UtcNow,
                    FailureCount = 1,
                    LastException = exception
                };
            }

            _logger.LogWarning("Node {NodeId} marked as failed, Exception: {Exception}", nodeId, exception.Message);
        }

        public void MarkNodeAsRecovered(string nodeId)
        {
            if (_failedNodes.TryRemove(nodeId, out var failedNode))
            {
                _logger.LogInformation("Node {NodeId} marked as recovered, Failure Count: {FailureCount}", 
                    nodeId, failedNode.FailureCount);
            }
        }

        public bool IsNodeFailed(string nodeId)
        {
            return _failedNodes.ContainsKey(nodeId);
        }

        public List<FailedNode> GetFailedNodes()
        {
            return _failedNodes.Values.ToList();
        }

        public FailoverStatistics GetFailoverStatistics()
        {
            var totalStats = new FailoverStatistics
            {
                TotalRequests = 0,
                SuccessfulRequests = 0,
                FailedRequests = 0,
                FailoverRequests = 0,
                AverageFailoverTime = 0,
                TotalFailoverTime = TimeSpan.Zero
            };

            foreach (var stats in _transactionStatistics.Values)
            {
                totalStats.TotalRequests += stats.TotalRequests;
                totalStats.SuccessfulRequests += stats.SuccessfulRequests;
                totalStats.FailedRequests += stats.FailedRequests;
                totalStats.FailoverRequests += stats.FailoverRequests;
                totalStats.TotalFailoverTime = totalStats.TotalFailoverTime.Add(stats.TotalFailoverTime);
            }

            if (totalStats.FailoverRequests > 0)
            {
                totalStats.AverageFailoverTime = totalStats.TotalFailoverTime.TotalMilliseconds / totalStats.FailoverRequests;
            }

            return totalStats;
        }

        /// <summary>
        /// 快速失败策略
        /// </summary>
        private async Task<T> ExecuteFailFastAsync<T>(
            Func<ClusterNode, Task<T>> operation,
            List<ClusterNode> clusterNodes,
            List<string> attemptedNodes,
            string? xid)
        {
            var selectedNode = _loadBalancer.SelectNode(clusterNodes);
            if (selectedNode == null)
            {
                throw new InvalidOperationException("No available nodes for operation");
            }

            attemptedNodes.Add(selectedNode.NodeId);

            try
            {
                var result = await operation(selectedNode);
                UpdateTransactionStatistics(xid, true, false, TimeSpan.Zero);
                return result;
            }
            catch (Exception ex)
            {
                MarkNodeAsFailed(selectedNode.NodeId, ex);
                UpdateTransactionStatistics(xid, false, false, TimeSpan.Zero);
                throw;
            }
        }

        /// <summary>
        /// 故障转移策略
        /// </summary>
        private async Task<T> ExecuteFailoverAsync<T>(
            Func<ClusterNode, Task<T>> operation,
            List<ClusterNode> clusterNodes,
            List<string> attemptedNodes,
            string? xid,
            string? key)
        {
            var config = _failoverConfiguration.CurrentValue;
            var startTime = DateTime.UtcNow;

            for (int attempt = 0; attempt < config.MaxRetryAttempts && attempt < clusterNodes.Count; attempt++)
            {
                var availableNodes = clusterNodes
                    .Where(n => !attemptedNodes.Contains(n.NodeId) && !IsNodeFailed(n.NodeId))
                    .ToList();

                if (!availableNodes.Any())
                {
                    break;
                }

                var selectedNode = _loadBalancer.SelectNode(availableNodes, key);
                if (selectedNode == null)
                {
                    break;
                }

                attemptedNodes.Add(selectedNode.NodeId);

                try
                {
                    var result = await operation(selectedNode);
                    
                    // 如果成功且之前有失败，更新故障转移统计
                    if (attempt > 0)
                    {
                        var failoverTime = DateTime.UtcNow - startTime;
                        UpdateTransactionStatistics(xid, true, true, failoverTime);
                        _logger.LogInformation("Operation succeeded after failover, Attempts: {Attempts}, Node: {NodeId}", 
                            attempt + 1, selectedNode.NodeId);
                    }
                    else
                    {
                        UpdateTransactionStatistics(xid, true, false, TimeSpan.Zero);
                    }

                    return result;
                }
                catch (Exception ex)
                {
                    MarkNodeAsFailed(selectedNode.NodeId, ex);
                    _logger.LogWarning("Operation failed on node {NodeId}, Attempt: {Attempts}, Exception: {Exception}", 
                        selectedNode.NodeId, attempt + 1, ex.Message);

                    if (attempt < config.MaxRetryAttempts - 1 && attempt < clusterNodes.Count - 1)
                    {
                        await Task.Delay(config.RetryDelayMilliseconds);
                    }
                }
            }

            // 所有尝试都失败
            UpdateTransactionStatistics(xid, false, attemptedNodes.Count > 1, DateTime.UtcNow - startTime);
            throw new InvalidOperationException($"All {attemptedNodes.Count} attempts failed.");
        }

        /// <summary>
        /// 安全重试策略
        /// </summary>
        private async Task<T> ExecuteSafeRetryAsync<T>(
            Func<ClusterNode, Task<T>> operation,
            List<ClusterNode> clusterNodes,
            List<string> attemptedNodes,
            string? xid,
            string? key)
        {
            var config = _failoverConfiguration.CurrentValue;
            var startTime = DateTime.UtcNow;

            for (int attempt = 0; attempt < config.MaxRetryAttempts; attempt++)
            {
                var availableNodes = clusterNodes
                    .Where(n => !attemptedNodes.Contains(n.NodeId) && !IsNodeFailed(n.NodeId))
                    .ToList();

                if (!availableNodes.Any())
                {
                    break;
                }

                var selectedNode = _loadBalancer.SelectNode(availableNodes, key);
                if (selectedNode == null)
                {
                    break;
                }

                attemptedNodes.Add(selectedNode.NodeId);

                try
                {
                    var result = await operation(selectedNode);
                    
                    // 如果成功且之前有失败，更新故障转移统计
                    if (attempt > 0)
                    {
                        var failoverTime = DateTime.UtcNow - startTime;
                        UpdateTransactionStatistics(xid, true, true, failoverTime);
                        _logger.LogInformation("Operation succeeded after safe retry, Attempts: {Attempts}, Node: {NodeId}", 
                            attempt + 1, selectedNode.NodeId);
                    }
                    else
                    {
                        UpdateTransactionStatistics(xid, true, false, TimeSpan.Zero);
                    }

                    return result;
                }
                catch (Exception ex)
                {
                    // 检查是否为可重试的异常
                    if (!IsRetryableException(ex))
                    {
                        MarkNodeAsFailed(selectedNode.NodeId, ex);
                        break;
                    }

                    _logger.LogWarning("Operation failed on node {NodeId}, Attempt: {Attempts}, Exception: {Exception}", 
                        selectedNode.NodeId, attempt + 1, ex.Message);

                    if (attempt < config.MaxRetryAttempts - 1)
                    {
                        await Task.Delay(config.RetryDelayMilliseconds);
                    }
                }
            }

            // 所有尝试都失败
            UpdateTransactionStatistics(xid, false, attemptedNodes.Count > 1, DateTime.UtcNow - startTime);
            throw new InvalidOperationException($"All {attemptedNodes.Count} attempts failed.");
        }

        /// <summary>
        /// 降级处理策略
        /// </summary>
        private async Task<T> ExecuteFallbackAsync<T>(
            Func<ClusterNode, Task<T>> operation,
            List<ClusterNode> clusterNodes,
            List<string> attemptedNodes,
            string? xid,
            string? key)
        {
            try
            {
                // 首先尝试正常执行
                return await ExecuteFailoverAsync(operation, clusterNodes, attemptedNodes, xid, key);
            }
            catch (Exception ex)
            {
                _logger.LogWarning("Primary operation failed, attempting fallback, Exception: {Exception}", ex.Message);
                
                // 尝试降级处理
                try
                {
                    var fallbackResult = await ExecuteFallbackOperationAsync<T>(xid);
                    UpdateTransactionStatistics(xid, true, true, TimeSpan.Zero);
                    return fallbackResult;
                }
                catch (Exception fallbackEx)
                {
                    _logger.LogError(fallbackEx, "Fallback operation also failed");
                    UpdateTransactionStatistics(xid, false, true, TimeSpan.Zero);
                    throw new InvalidOperationException("Both primary and fallback operations failed", fallbackEx);
                }
            }
        }

        /// <summary>
        /// 执行降级操作
        /// </summary>
        private async Task<T> ExecuteFallbackOperationAsync<T>(string? xid)
        {
            // 这里实现降级逻辑，例如：
            // 1. 返回默认值
            // 2. 从缓存中获取
            // 3. 使用本地数据
            // 4. 执行简化的业务逻辑

            _logger.LogInformation("Executing fallback operation for transaction {Xid}", xid);

            // 默认实现：返回类型的默认值
            // 在生产环境中，应该根据业务需求实现具体的降级逻辑
            // 例如：从缓存获取数据、返回预设默认值、执行简化逻辑等
            await Task.CompletedTask; // 保持异步方法签名

            _logger.LogWarning("Using default fallback: returning default value for type {Type}", typeof(T).Name);
            return default(T);
        }

        /// <summary>
        /// 检查异常是否可重试
        /// </summary>
        private bool IsRetryableException(Exception exception)
        {
            // 这里定义哪些异常是可重试的
            // 例如：网络超时、连接拒绝等临时性错误

            if (exception is TimeoutException ||
                exception is System.Net.Http.HttpRequestException ||
                (exception is System.Net.Sockets.SocketException socketEx && 
                 (socketEx.SocketErrorCode == System.Net.Sockets.SocketError.TimedOut ||
                  socketEx.SocketErrorCode == System.Net.Sockets.SocketError.ConnectionRefused)))
            {
                return true;
            }

            // 检查异常消息
            var message = exception.Message.ToLowerInvariant();
            if (message.Contains("timeout") || 
                message.Contains("connection") || 
                message.Contains("network") ||
                message.Contains("temporary"))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 更新事务统计信息
        /// </summary>
        private void UpdateTransactionStatistics(string? xid, bool success, bool failover, TimeSpan failoverTime)
        {
            if (string.IsNullOrEmpty(xid))
            {
                return;
            }

            if (!_transactionStatistics.TryGetValue(xid, out var stats))
            {
                stats = new FailoverStatistics { TransactionId = xid };
                _transactionStatistics[xid] = stats;
            }

            stats.TotalRequests++;

            if (success)
            {
                stats.SuccessfulRequests++;
            }
            else
            {
                stats.FailedRequests++;
            }

            if (failover)
            {
                stats.FailoverRequests++;
                stats.TotalFailoverTime = stats.TotalFailoverTime.Add(failoverTime);
            }
        }

        /// <summary>
        /// 检查故障节点
        /// </summary>
        private async Task CheckFailedNodesAsync()
        {
            try
            {
                var config = _failoverConfiguration.CurrentValue;
                var now = DateTime.UtcNow;
                var recoveryThreshold = TimeSpan.FromSeconds(config.NodeRecoveryTimeoutSeconds);

                foreach (var failedNode in _failedNodes.Values.ToList())
                {
                    // 检查是否达到恢复条件
                    if (now - failedNode.LastFailureTime > recoveryThreshold)
                    {
                        // 尝试连接节点，检查是否恢复
                        try
                        {
                            var node = _clusterManager.GetClusterNodes()
                                .FirstOrDefault(n => n.NodeId == failedNode.NodeId);

                            if (node != null)
                            {
                                // 发送心跳检查节点状态
                                var heartbeatResult = await _clusterManager.SendHeartbeatAsync(node.NodeId);
                                if (heartbeatResult)
                                {
                                    MarkNodeAsRecovered(failedNode.NodeId);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogDebug(ex, "Error checking failed node {NodeId}", failedNode.NodeId);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error checking failed nodes");
            }
        }

        public void Dispose()
        {
            if (!_disposed)
            {
                _recoveryTimer?.Dispose();
                _disposed = true;
            }
        }
    }

    /// <summary>
    /// 故障节点信息
    /// </summary>
    public class FailedNode
    {
        /// <summary>
        /// 节点ID
        /// </summary>
        public string NodeId { get; set; } = string.Empty;

        /// <summary>
        /// 首次失败时间
        /// </summary>
        public DateTime FirstFailureTime { get; set; }

        /// <summary>
        /// 最后失败时间
        /// </summary>
        public DateTime LastFailureTime { get; set; }

        /// <summary>
        /// 失败次数
        /// </summary>
        public int FailureCount { get; set; }

        /// <summary>
        /// 最后一次失败的异常
        /// </summary>
        public Exception? LastException { get; set; }
    }

    /// <summary>
    /// 故障转移统计信息
    /// </summary>
    public class FailoverStatistics
    {
        /// <summary>
        /// 事务ID
        /// </summary>
        public string? TransactionId { get; set; }

        /// <summary>
        /// 总请求数
        /// </summary>
        public long TotalRequests { get; set; }

        /// <summary>
        /// 成功请求数
        /// </summary>
        public long SuccessfulRequests { get; set; }

        /// <summary>
        /// 失败请求数
        /// </summary>
        public long FailedRequests { get; set; }

        /// <summary>
        /// 故障转移请求数
        /// </summary>
        public long FailoverRequests { get; set; }

        /// <summary>
        /// 平均故障转移时间（毫秒）
        /// </summary>
        public double AverageFailoverTime { get; set; }

        /// <summary>
        /// 总故障转移时间
        /// </summary>
        public TimeSpan TotalFailoverTime { get; set; }
    }

    /// <summary>
    /// 故障转移配置
    /// </summary>
    public class FailoverConfiguration
    {
        /// <summary>
        /// 故障转移策略
        /// </summary>
        public FailoverStrategy Strategy { get; set; } = FailoverStrategy.Failover;

        /// <summary>
        /// 最大重试次数
        /// </summary>
        public int MaxRetryAttempts { get; set; } = 3;

        /// <summary>
        /// 重试延迟（毫秒）
        /// </summary>
        public int RetryDelayMilliseconds { get; set; } = 1000;

        /// <summary>
        /// 节点恢复超时（秒）
        /// </summary>
        public int NodeRecoveryTimeoutSeconds { get; set; } = 300;

        /// <summary>
        /// 恢复检查间隔（秒）
        /// </summary>
        public int RecoveryCheckIntervalSeconds { get; set; } = 60;

        /// <summary>
        /// 是否启用降级
        /// </summary>
        public bool EnableFallback { get; set; } = false;

        /// <summary>
        /// 降级超时（毫秒）
        /// </summary>
        public int FallbackTimeoutMilliseconds { get; set; } = 5000;
    }
}